﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Security.Cryptography;
using System.Xml;
using System.IO;
using System.Data;
using System.Configuration;
using System.Web;
using System.Drawing;
using System.Runtime.Serialization.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net;
using NPOI.HPSF;
using System.Security.Cryptography.X509Certificates;
using System.Net.Http;
using System.Net.Security;
using Newtonsoft.Json;
using System.Drawing.Imaging;

namespace Oliving.Edge.Common.Helper
{
    public static class CommHelper
    {
        #region 变量

        #endregion

        #region 属性

        #endregion

        #region 构造

        #endregion


        #region 公有方法

        #region 生成主键ID
        /// <summary>
        /// 生成主键ID
        /// </summary>
        /// <param name="prefix">前缀</param>
        /// <returns></returns>
        public static string CreatePKID(string prefix)
        {
            if (string.IsNullOrWhiteSpace(prefix))
                throw new Exception("前缀不可以为空！");
            else if (prefix.Length > 4)
                throw new Exception("前缀长度不可大于4位字符！");

            long i = 1;
            foreach (byte b in Guid.NewGuid().ToByteArray())
                i *= ((int)b + 1);
            string pk_id = string.Format("{0:x}", i - DateTime.Now.Ticks);

            pk_id = prefix + pk_id;
            int len = 20;
            len = len - pk_id.Length;
            string rdm = DateTime.Now.ToString("yyyyMMddHHmmssfff");
            pk_id = pk_id + rdm.Substring(rdm.Length - len, len);

            return pk_id;
        }
        /// <summary>
        public static string GetCode(int num)
        {
            string a = "0123456789";
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < num; i++)
            {
                sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
            }
            return sb.ToString();
        }
        #endregion

        #region MD5
        ///   <summary>
        ///   给一个字符串进行MD5加密
        ///   </summary>
        ///   <param   name="strText">待加密字符串</param>
        ///   <returns>加密后的字符串</returns>
        public static string MD5Encrypt(string strText)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(strText)), 4, 8);
            t2 = t2.Replace("-", "");

            t2 = t2.ToLower();
            return t2;
        }
        #endregion

        #region 年龄计算
        /// <summary>
        /// 年龄计算
        /// </summary>
        /// <param name="birthdate"></param>
        /// <returns></returns>
        public static int Age(DateTime birthdate)
        {
            DateTime timeNow = DateTime.Now;
            int age = timeNow.Year - birthdate.Year;
            age = timeNow >= birthdate ? age : age - 1;
            return age;
        }
        #endregion

        #region string.IsNullOrWhiteSpace 方法

        public static bool IsNullOrWhiteSpace(List<string> parm)
        {
            if (parm == null || parm.Count == 0)
                return true;
            foreach (var item in parm)
            {
                if (string.IsNullOrWhiteSpace(item))
                    return true;
            }
            return false;
        }
        public static bool IsNullOrWhiteSpace(params string[] parm) => IsNullOrWhiteSpace(parm?.ToList());
        public static bool IsNullOrWhiteSpace(this string parm) => string.IsNullOrWhiteSpace(parm);

        #endregion

        #region Obj Is Null 方法

        public static bool IsNull<T>(List<T> list)
        {
            if (list == null)
                return true;
            foreach (var item in list)
            {
                if (item == null)
                    return true;
            }
            return false;
        }

        public static bool IsNull<T>(params T[] parm) => IsNull(parm?.ToList());

        public static bool IsNull<T>(this T parm) => parm == null;

        #endregion

        #region Get Obj Is Null Name

        public static string GetNullStr<T>(List<T> list)
            where T : class
        {
            if (list == null)
                return $"{nameof(list)}为null";
            foreach (var item in list)
            {
                if (item == null)
                    return $"{nameof(item)}为null";
            }
            return "";
        }
        public static string GetNullStr<T>(params T[] parm) where T : class => GetNullStr(parm?.ToList());

        public static string GetNullStr<T>(this T parm) where T : class => $"{nameof(parm)}为null";

        #endregion

        #region string.GetNullOrWiterSpace Param Name

        public static string GetNullOrWhiteSpaceStr(List<string> parm)
        {
            if (parm == null || parm.Count == 0)
                return $"{nameof(parm)} 为null";
            foreach (var item in parm)
            {
                if (string.IsNullOrWhiteSpace(item))
                    return $"{nameof(item)} 为null";
            }
            return "成功";
        }
        public static string GetNullOrWhiteSpaceStr(params string[] parm) => GetNullOrWhiteSpaceStr(parm?.ToList());
        public static string GetNullOrWhiteSpaceStr(this string parm) => $"{nameof(parm)} 为null";

        #endregion

        #region CheckedTime

        public static bool Checked(List<DateTime> parm)
        {
            if (parm == null || parm.Count == 0)
                return true;
            DateTime minVal = Convert.ToDateTime("1753-1-1");
            foreach (var item in parm)
            {
                if (item < minVal)
                    return true;
            }
            return false;
        }
        public static bool Checked(params DateTime[] parm) => Checked(parm.ToList());
        public static bool Checked(this DateTime parm) => parm < Convert.ToDateTime("1753-1-1");

        public static bool CheckedDate(this string date) => Checked(Convert.ToDateTime(date));

        #endregion

        #region CompareTo Time

        public static int CompareTo(this DateTime time, char format, DateTime compareTime)
        {
            switch (format)
            {
                case 'y':
                    time = Convert.ToDateTime(time.ToString("yyyy"));
                    compareTime = Convert.ToDateTime(time.ToString("yyyy"));
                    break;
                case 'M':
                    time = Convert.ToDateTime(time.ToString("yyyy-MM"));
                    compareTime = Convert.ToDateTime(time.ToString("yyyy-MM"));
                    break;
                case 'd':
                    time = Convert.ToDateTime(time.ToString("yyyy-MM-dd"));
                    compareTime = Convert.ToDateTime(time.ToString("yyyy-MM-dd"));
                    break;
                case 'H':
                    time = Convert.ToDateTime(time.ToString("yyyy-MM-dd HH"));
                    compareTime = Convert.ToDateTime(time.ToString("yyyy-MM-dd HH"));
                    break;
                case 'm':
                    time = Convert.ToDateTime(time.ToString("yyyy-MM-dd HH:mm"));
                    compareTime = Convert.ToDateTime(time.ToString("yyyy-MM-dd HH:mm"));
                    break;
            }
            return time.CompareTo(compareTime);
        }

        #endregion

        #region string.IsNum
        public static bool IsNum(this string str)
        {
            foreach (var item in str)
            {
                var b = Convert.ToByte(item);
                if (b < 48 || b > 57)
                    return false;
            }
            return true;
        }
        public static bool IsNum(this char str) => IsNum(str.ToString());

        #endregion


        #region 将泛类型集合List类转换成DataTable
        /// <summary>
        /// 将泛类型集合List类转换成DataTable
        /// </summary>
        /// <param name="list">泛类型集合</param>
        /// <returns></returns>
        public static DataTable ListToDataTable<T>(List<T> entitys)
        {
            //检查实体集合不能为空
            if (entitys == null || entitys.Count < 1)
            {
                throw new Exception("需转换的集合为空");
            }
            //取出第一个实体的所有Propertie
            Type entityType = entitys[0].GetType();
            PropertyInfo[] entityProperties = entityType.GetProperties();

            //生成DataTable的structure
            //生产代码中，应将生成的DataTable结构Cache起来，此处略
            DataTable dt = new DataTable();
            for (int i = 0; i < entityProperties.Length; i++)
            {
                //dt.Columns.Add(entityProperties[i].Name, entityProperties[i].PropertyType);
                dt.Columns.Add(entityProperties[i].Name);
            }
            //将所有entity添加到DataTable中
            foreach (object entity in entitys)
            {
                //检查所有的的实体都为同一类型
                if (entity.GetType() != entityType)
                {
                    throw new Exception("要转换的集合元素类型不一致");
                }
                object[] entityValues = new object[entityProperties.Length];
                for (int i = 0; i < entityProperties.Length; i++)
                {
                    entityValues[i] = entityProperties[i].GetValue(entity, null);
                }
                dt.Rows.Add(entityValues);
            }
            return dt;
        }
        #endregion


        #region 映射相同实体类
        //数据成员的别名
        [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
            AllowMultiple = false, Inherited = true)]
        public class DataMemberAliasAttribute : System.Attribute
        {
            private readonly string _alias;

            public DataMemberAliasAttribute(string alias)
            {
                _alias = alias;
            }

            public string Alias
            {
                get
                {
                    return _alias;
                }
            }
        }
        private static T Mapping<T>(this object source) where T : class
        {
            Type t = typeof(T);

            if (source == null)
            {
                return default(T);
            }

            T target = (T)t.Assembly.CreateInstance(t.FullName);

            #region Mapping Properties
            PropertyInfo[] targetProps = t.GetProperties();
            if (targetProps != null && targetProps.Length > 0)
            {
                string targetPropName;  //目标属性名称
                PropertyInfo sourceProp;
                object sourcePropValue;
                foreach (PropertyInfo targetProp in targetProps)
                {
                    //优先使用数据成员的别名，如果没有别名则使用属性名
                    object[] targetPropAliasAttrs = targetProp.GetCustomAttributes(typeof(DataMemberAliasAttribute), true);
                    if (targetPropAliasAttrs != null && targetPropAliasAttrs.Length > 0)
                        targetPropName = ((DataMemberAliasAttribute)targetPropAliasAttrs[0]).Alias;
                    else
                        targetPropName = targetProp.Name;

                    //检索源属性
                    sourceProp = source.GetType().GetProperty(targetPropName);
                    if (sourceProp != null && sourceProp.CanRead && targetProp.CanRead)
                    {
                        sourcePropValue = sourceProp.GetValue(source, null);
                        //属性类型一致时，直接填充属性值
                        if (targetProp.PropertyType == sourceProp.PropertyType)
                            targetProp.SetValue(target, sourcePropValue, null);
                    }
                }
            }
            #endregion

            #region Mapping Fields
            FieldInfo[] targetFields = t.GetFields();
            if (targetFields != null && targetFields.Length > 0)
            {
                string targetFieldName;
                FieldInfo sourceField;
                foreach (FieldInfo targetField in targetFields)
                {
                    if (!targetField.IsInitOnly && !targetField.IsLiteral)
                    {//字段可以被赋值
                        object[] targetFieldAttrs = targetField.GetCustomAttributes(typeof(DataMemberAliasAttribute), true);
                        if (targetFieldAttrs != null && targetFieldAttrs.Length > 0)
                            targetFieldName = ((DataMemberAliasAttribute)targetFieldAttrs[0]).Alias;
                        else
                            targetFieldName = targetField.Name;

                        sourceField = source.GetType().GetField(targetFieldName);
                        if (sourceField != null)
                        {
                            //数据类型相同时映射值
                            if (targetField.FieldType == sourceField.FieldType)
                                targetField.SetValue(target, sourceField.GetValue(source));
                        }
                    }
                }
            }
            #endregion

            return target;
        }

        public static TOut Mapping<TOut, TIn>(this TIn source)
            where TIn : class
            where TOut : class
        {
            return source.Mapping<TOut>();
        }
        #endregion

        #region Josn转List  List转Json
        /// <summary>
        /// JSON序列化
        /// </summary>
        public static string JsonSerializer<T>(T t)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                ser.WriteObject(ms, t);
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }

        /// <summary>
        /// JSON反序列化
        /// </summary>
        public static T JsonDeserialize<T>(string jsonString)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
            {
                return (T)ser.ReadObject(ms);
            }
        }

        #endregion


        #region 下载文件到本地

        #endregion

        #region 第三方调用 
        public static async Task<string> HttpGetAsync(string url)
        {
            var request = CreateRequest(url, HttpMethod.Get);
            return await GetResponseStringAsync(request);
        }
        public static async Task<string> HttpPostAsync(string url,string postData)
        {
            var request = CreateRequest(url, HttpMethod.Post, postData);
            return await GetResponseStringAsync(request);
        }
        public static async Task<string> HttpJsonAsync(string url, object postData)
        {
            var request = CreateJsonRequest(url, HttpMethod.Post, postData);
            return await GetResponseStringAsync(request);
        }
        private static HttpWebRequest CreateJsonRequest(string url, HttpMethod method, object postData, string certpath = "", string certpwd = "")
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method.ToString();
            request.ContentType = "application/json; charset=utf-8";
            request.Accept = "*/*";
            request.Timeout = 15000;
            request.AllowAutoRedirect = false;
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((a, b, c, d) => true);
            if (!string.IsNullOrEmpty(certpath) && !string.IsNullOrEmpty(certpwd))
            {
                X509Certificate2 cer = new X509Certificate2(certpath, certpwd,
                    X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
                request.ClientCertificates.Add(cer);
            }
            if (method == HttpMethod.Post)
            {
                using (var sw = new StreamWriter(request.GetRequestStream()))
                {
                    sw.Write(postData);
                }
            }
            return request;
        }
        private static HttpWebRequest CreateRequest(string url, HttpMethod method, string postData = "", string certpath = "", string certpwd = "")
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method.ToString();
            request.ContentType = "application/x-www-form-urlencoded";
            request.Accept = "*/*";
            request.Timeout = 15000;
            request.AllowAutoRedirect = false;
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((a, b, c, d) => true);
            if (!string.IsNullOrEmpty(certpath) && !string.IsNullOrEmpty(certpwd))
            {
                X509Certificate2 cer = new X509Certificate2(certpath, certpwd,
                    X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
                request.ClientCertificates.Add(cer);
            }
            if (method == HttpMethod.Post)
            {
                using (var sw = new StreamWriter(request.GetRequestStream()))
                {
                    sw.Write(postData);
                }
            }
            return request;
        }

        private static async Task<string> GetResponseStringAsync(HttpWebRequest request)
        {
            using (var response = await request.GetResponseAsync() as HttpWebResponse)
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return reader.ReadToEnd();//获取响应
                }
            }
        }
        /// <summary>
        /// 发起GET请求，并获取请求返回值
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="url">接口地址</param>
        public static async Task<T> GetResultAsync<T>(string url)
        {
            var retdata = await HttpGetAsync(url);
            return JsonConvert.DeserializeObject<T>(retdata);
        }
        /// <summary>
        /// 发起GET请求，并获取请求返回值
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="url">接口地址</param>
        public static async Task<T> PostResultAsync<T>(string url,string postData)
        {
            var retdata = await HttpPostAsync(url, postData);
            return JsonConvert.DeserializeObject<T>(retdata);
        }
        /// <summary>
        /// 发起GET请求，并获取请求返回值
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="url">接口地址</param>
        public static async Task<T> PostJsonAsync<T>(string url, object postData)
        {
            var retdata = await HttpJsonAsync(url, postData);
            return JsonConvert.DeserializeObject<T>(retdata);
        }
        #endregion



    }
    #endregion



}
